package com.potenza.wxuser.aop;

import com.google.common.util.concurrent.RateLimiter;
import com.potenza.wxuser.annotation.RateLimit;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

@Aspect
@Component
public class RateLimitAspect {

    /**
     * 切入点
     * 匹配包及其子包下的所有类的所有方法
     * Pointcut annotation
     */
    @Pointcut("@annotation(com.potenza.wxuser.annotation.RateLimit)")
    public void pointCut_rateLimitAspect(){

    }

    private Map<String, RateLimiter> rateLimiterMap = new HashMap<>();


    @Before("pointCut_rateLimitAspect()")
    public void beforeAdvice(JoinPoint pjp) throws Throwable {

        MethodSignature signature = (MethodSignature) pjp.getSignature();
        Method method = signature.getMethod();

        String className = pjp.getTarget().getClass().getName();
        String methodName = signature.getName();
        String key  = className + "." + methodName;
        RateLimiter rateLimiter = rateLimiterMap.get(key);
        if(rateLimiter==null){
            rateLimiter = RateLimiter.create(1);
            rateLimiterMap.put(key,rateLimiter);
        }

        if (method.isAnnotationPresent(RateLimit.class)) {
            RateLimit rl = method.getAnnotation(RateLimit.class);
            rateLimiter.setRate(rl.perSecond());
            if (!rateLimiter.tryAcquire(rl.timeOut(), rl.timeOutUnit())) {
                throw new Exception("访问人数太多,请稍后再试试");
            }
        }
    }
}
